/* File:        	PEP.java
* Package:			com.tecnalia.authz.pep
* Created:      	29-abr-2011
* Last Changed: 	0:11:09
* Author:       	Borja Urkizu borja.urquizu@tecnalia.com
*
*   
* History:
*  Revision 1.0.0.0  
* 
* Tecnalia Research and Innovation
*/
package com.tecnalia.authz.pep;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringWriter;
import java.io.Writer;

import org.jboss.security.xacml.interfaces.RequestContext;
import org.jboss.security.xacml.interfaces.ResponseContext;

import com.tecnalia.authz.common.Resource;
import com.tecnalia.authz.common.XACMLConstants;
import com.tecnalia.authz.common.request.Request;
import com.tecnalia.authz.log.PEPLog;
import com.tecnalia.authz.pep.comm.Client;
import com.tecnalia.authz.pep.config.PEPConfig;
import com.tecnalia.authz.pep.interfaces.ServiceXACML;

// TODO: Auto-generated Javadoc
/**
 * The Class PEP.
 */
public class PEP implements ServiceXACML{
	
		/** The logger. */
		public static PEPLog logger = new PEPLog(PEP.class);
		
		/** The pepconfig. */
		private PEPConfig pepconfig;

		/** The client. */
	   	//static final long serialVersionUID = 1L;
		   
	   	/** The client. */
	   	private Client client = null;
		  
		/** The Constant DECISION_PERMIT. */
		public static final int DECISION_PERMIT = 0;
		
		/** The Constant DECISION_DENY. */
		public static final int DECISION_DENY = 1;
		
		/** The Constant DECISION_INDETERMINATE. */
		public static final int DECISION_INDETERMINATE = 2;
		
		/** The Constant DECISION_NOT_APPLICABLE. */
		public static final int DECISION_NOT_APPLICABLE = 3;
	
		/**
		 * Instantiates a new pEP.
		 */
	   	public PEP() {
			pepconfig = new PEPConfig();   
	   		client = new Client(pepconfig.getPDPDaemonHost(), pepconfig.getPDPDaemonPort());
	   	}

	   
		// Evaluate the list of request against PDP which may hold 100, 1000 or 10000 policies. Let PDP retrieve
		// the matchable policies and evaluate them
		/* (non-Javadoc)
		 * @see com.tecnalia.authz.pep.interfaces.ServiceXACML#evaluateFlexibleRequest(java.lang.String, java.lang.String[], java.lang.String)
		 */
		@Override
		public String[] evaluateFlexibleRequest(String subject,
				String[] serviceList, String action) throws Exception {
			
			
			logger.info(pepconfig.getID() + " EvaluateFlexibleRequest");
			
			//Create the List of request to evaluate 
			RequestContext[] request = new RequestContext[1];  
			Request req = new Request();
			request[0] = req.CreateRequestAttrList(subject, serviceList, action, "non-functional-role");			
			logger.logBinaryRequest(request[0]);
			
			
			//Object to hold the XACML evaluate Response
			ResponseContext[] responseContext = null;				

	        try {
	        	responseContext = client.XACMLquery(request, 
	        										pepconfig.getID(),
	        										pepconfig.getName(),
	        										XACMLConstants.XACML_QUERY_Flexible);
				if(responseContext.length >= 2){
					logger.info("XACML Request ID ERROR in a flexible XACMLQuery " +
								"more than 1 response it's not allowed:");
				}
				logger.logBinaryResponse(responseContext[0]);
				
				String[] subjectSplit = responseContext[0].getResult().getResourceId().split(",");				

				return subjectSplit;
			} catch (Exception e) {
				e.printStackTrace();
			}
			
			String[] subjectSplit = {"XACML query not stablished."};
			
			
			return subjectSplit;
		}


		/* Evaluate the list of request against PDP which may hold 100, 1000 or 10000 policies. Let PDP retrieve 
		 * the matchable policies and evaluate them
		 * 
		 * @see com.tecnalia.authz.pep.interfaces.ServiceXACML#evaluateStrictRequest(java.lang.String, java.lang.String[], java.lang.String)
		 */
		@Override
		public int evaluateStrictRequest(String subject,
				String[] serviceList, String action) throws Exception {

			logger.info(pepconfig.getID() + " EvaluateStrictRequest");

			
			//Create the List of request to evaluate 
			RequestContext[] request = new RequestContext[1];  
			Request req = new Request();
			request[0] = req.CreateRequestAttrList(subject, serviceList, action, "non-functional-role");
			
			//Object to hold the XACML evaluate Response
			ResponseContext[] responseContext = null;				

	        try {
	        	responseContext = client.XACMLquery(request, 
						pepconfig.getID(),
						pepconfig.getName(),
						XACMLConstants.XACML_QUERY_Strict);

	        	if(responseContext == null){
					logger.info("XACML Request ID ERROR in a flexible XACMLQuery " +
											"more than 1 response it's not allowed:");
				}
		        return responseContext[0].getDecision();
			} catch (Exception e) {
				e.printStackTrace();
			}
			
			return XACMLConstants.XACML_QUERY_NOT_STABLISHED;
	    }
		
		/* (non-Javadoc)
		 * @see com.tecnalia.authz.pep.interfaces.ServiceXACML#evaluateRequest(java.lang.String, java.lang.String, java.lang.String, java.lang.String)
		 */
		@Override
		public int evaluateRequest(String subject, String roleGroup,
						String resID, String action) throws Exception {
			
			//Create the List of request to evaluate, in this case only one 
			RequestContext[] request = new RequestContext[1];  
			Request req = new Request();
			request[0] = req.CreateRequest(subject, resID, action, roleGroup);
			
			//Object to hold the XACML evaluate Response
			ResponseContext[] responseContext = null;				

	        try {
	        	responseContext = client.XACMLquery(request, 
													pepconfig.getID(),
													pepconfig.getName(),
													XACMLConstants.XACML_QUERY_Simple);
				if(responseContext.length >= 2){
					//this.logger.error("XACML Request ID ERROR in a flexible XACMLQuery " +
					//						"more than 1 response it's not allowed:");
				}

		        return responseContext[0].getDecision();
			} catch (Exception e) {
				e.printStackTrace();
			}
			
			return XACMLConstants.XACML_QUERY_NOT_STABLISHED;

		}



		/* (non-Javadoc)
		 * @see com.tecnalia.authz.pep.interfaces.ServiceXACML#getAuthorizacionAndAccess(java.lang.String, java.lang.String, java.lang.String, java.lang.String)
		 */
		@Override
		public String getAuthorizacionAndAccess(String subject, String roleGroup, String resource, String action){
			//Evaluate using Simple
			int decision = this.getAuthorizacion(subject, roleGroup, resource, action);
			   
			//Set by default deny access
			String file = subject + " don't have permision to " + action + " the " + resource;
			//Access the resource. Just for testing porpouses sent to stdout the content of the file
			if( decision == PEP.DECISION_PERMIT) {
				
				Resource resFile = new Resource(); 
				InputStream is = resFile.getResourceAsStream(resource);
				try {
					file = this.convertStreamToString(is);
				} catch (IOException e) {
					e.printStackTrace();
				}					
			}
				
			return file;
		}
	   
	   
	   /* (non-Javadoc)
   	 	* @see com.tecnalia.authz.pep.interfaces.ServiceXACML#getAuthorizacion(java.lang.String, java.lang.String, java.lang.String, java.lang.String)
   	 	*/
	   	@Override
		public int getAuthorizacion(String subject, String roleGroup, String resource, String action){
		   	//Evaluate using simple  
		   	int response = DECISION_INDETERMINATE;
			try {
				response = this.evaluateRequest(subject,roleGroup, resource,action);
			} catch (Exception e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
			
			return response;
		}  	
			

	   
	   
	    /**
    	 * Convert stream to string.
    	 *
    	 * @param is the is
    	 * @return the string
    	 * @throws IOException Signals that an I/O exception has occurred.
    	 */
    	private String convertStreamToString(InputStream is) throws IOException {
		    /*
		     * To convert the InputStream to String we use the
		     * Reader.read(char[] buffer) method. We iterate until the
		     * Reader return -1 which means there's no more data to
		     * read. We use the StringWriter class to produce the string.
		     */
		    if (is != null) {
		        Writer writer = new StringWriter();
		
		        char[] buffer = new char[1024];
		        try {
		            Reader reader = new BufferedReader(
		                    new InputStreamReader(is, "UTF-8"));
		            int n;
		            while ((n = reader.read(buffer)) != -1) {
		                writer.write(buffer, 0, n);
		            }
		        } finally {
		            is.close();
		        }
		        return writer.toString();
		    } else {        
		        return "";
		    }
	    }



}
